home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / kernel.c < prev    next >
C/C++ Source or Header  |  1993-11-17  |  13KB  |  544 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. #define    SUSPEND_PROC    1
  6. #undef    PROCTRACE    1    /* kernel debugging */
  7. #undef    PROCLOG        1    /* debugging */
  8.  
  9. #if    defined(PROCLOG) || defined(PROCTRACE)
  10. #include <stdio.h>
  11. #endif
  12. #include <dos.h>
  13. #include <setjmp.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "proc.h"
  17. #include "timer.h"
  18. #include "socket.h"
  19. #include "daemon.h"
  20. #include "hardware.h"
  21.  
  22. #ifdef    PROCLOG
  23. FILE *proclog;
  24. FILE *proctrace;
  25. #endif
  26. int Stkchk = 0;
  27. struct proc *Curproc;        /* Currently running process */
  28. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  29. struct proc *Waittab[PHASH];    /* Waiting process list */
  30. struct proc *Susptab;        /* Suspended processes */
  31. static struct mbuf *Killq;
  32.  
  33. static void addproc __ARGS((struct proc *entry));
  34. static void delproc __ARGS((struct proc *entry));
  35.  
  36. /* Create a process descriptor for the main function. Must be actually
  37.  * called from the main function!
  38.  * Note that standard I/O is NOT set up here.
  39.  */
  40. struct proc *
  41. mainproc(name)
  42. char *name;
  43. {
  44.     register struct proc *pp;
  45.     register unsigned k;
  46.     register int16 *p;
  47.  
  48.     /* Create process descriptor */
  49.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  50.  
  51.     /* Create name */
  52.     pp->name = strdup(name);
  53. #ifndef    AMIGA
  54.     pp->stksize = _stklen / sizeof(int16);
  55. #ifndef TNOS_68K
  56.     pp->stack = (p = MK_FP(_SS,0));
  57.     k = _SP / sizeof(int16);
  58.         while(k-- > 0) *p++ = STACKPAT;
  59. #else
  60.     pp->stack = 0;
  61.     pp->stksize = 0;
  62. #endif
  63. #else
  64.     init_psetup(pp);
  65. #endif
  66.     /* Make current */
  67.     pp->state = READY;
  68.     Curproc = pp;
  69.  
  70. #ifdef    PROCLOG
  71.     proclog = fopen("proclog",APPEND_TEXT);
  72.     proctrace = fopen("proctrace",APPEND_TEXT);
  73. #endif
  74.     return pp;
  75. }
  76. /* Create a new, ready process and return pointer to descriptor.
  77.  * The general registers are not initialized, but optional args are pushed
  78.  * on the stack so they can be seen by a C function.
  79.  */
  80. struct proc *
  81. newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
  82. char *name;        /* Arbitrary user-assigned name string */
  83. unsigned int stksize;    /* Stack size in words to allocate */
  84. void (*pc)();        /* Initial execution address */
  85. int iarg;        /* Integer argument (argc) */
  86. void *parg1;        /* Generic pointer argument #1 (argv) */
  87. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  88. int freeargs;        /* If set, free arg list on parg1 at termination */
  89. {
  90.     register struct proc *pp;
  91.     int i;
  92.  
  93.     if(Stkchk)
  94.         chkstk();
  95.  
  96.     /* Create process descriptor */
  97.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  98.  
  99.     /* Create name */
  100.     pp->name = strdup(name);
  101.  
  102.     /* Allocate stack */
  103. #ifdef    AMIGA
  104.     stksize += 2000;    /* DOS overhead */
  105. #endif
  106. #ifdef TNOS_68K
  107.     stksize += 128;
  108. #endif
  109.     pp->stksize = stksize;
  110.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  111.         free(pp->name);
  112.         free((char *)pp);
  113.         return NULLPROC;
  114.     }
  115.     /* Initialize stack for high-water check */
  116.     for(i=0;i<stksize;i++)
  117.         pp->stack[i] = STACKPAT;
  118.  
  119.     /* Do machine-dependent initialization of stack */
  120.     psetup(pp,iarg,parg1,parg2,pc);
  121.  
  122.     pp->freeargs = freeargs;
  123.     pp->iarg = iarg;
  124.     pp->parg1 = parg1;
  125.     pp->parg2 = parg2;
  126.     
  127.     /* Inherit creator's input and output sockets */
  128.     usesock(Curproc->input);
  129.     pp->input = Curproc->input;
  130.     usesock(Curproc->output);
  131.     pp->output = Curproc->output;
  132.  
  133.     /* Add to ready process table */
  134.     pp->state = READY;
  135.     addproc(pp);
  136.     return pp;
  137. }
  138.  
  139. /* Free resources allocated to specified process. If a process wants to kill
  140.  * itself, the reaper is called to do the dirty work. This avoids some
  141.  * messy situations that would otherwise occur, like freeing your own stack.
  142.  */
  143. void
  144. killproc(pp)
  145. register struct proc *pp;
  146. {
  147.     char **argv;
  148.  
  149.     if(pp == NULLPROC)
  150.         return;
  151.     /* Don't check the stack here! Will cause infinite recursion if
  152.      * called from a stack error
  153.      */
  154.  
  155.     if(pp == Curproc)
  156.         killself();    /* Doesn't return */
  157.  
  158.     /* Close any open sockets */
  159.     freesock(pp);
  160.  
  161.     close_s(pp->input);
  162.     close_s(pp->output);
  163.  
  164.     /* Stop alarm clock in case it's running */
  165.     stop_timer(&pp->alarm);
  166.  
  167.     /* Alert everyone waiting for this proc to die */
  168.     psignal(pp,0);
  169.  
  170.     /* Remove from appropriate table */
  171.     delproc(pp);
  172.  
  173. #ifdef    PROCLOG
  174.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  175.         pp->name,stkutil(pp),pp->stksize);
  176.     fclose(proclog);
  177.     proclog = fopen("proclog",APPEND_TEXT);
  178.     proctrace = fopen("proctrace",APPEND_TEXT);
  179. #endif
  180.     /* Free allocated memory resources */
  181.     if(pp->freeargs == 1){
  182.         argv = pp->parg1;
  183.         while(pp->iarg-- != 0)
  184.             free(*argv++);
  185.         free(pp->parg1);
  186.     }
  187.     if(pp->freeargs == 2)
  188.         free(pp->parg2);
  189.     free(pp->name);
  190.     free(pp->stack);
  191.     free(pp->outbuf);
  192.     free((char *)pp);
  193. }
  194. /* Terminate current process by sending a request to the killer process.
  195.  * Automatically called when a process function returns. Does not return.
  196.  */
  197. void
  198. killself()
  199. {
  200.     register struct mbuf *bp;
  201.  
  202.     if(Curproc != NULLPROC){
  203.         bp = pushdown(NULLBUF,sizeof(Curproc));
  204.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  205.         enqueue(&Killq,bp);
  206.     }
  207.     /* "Wait for me; I will be merciful and quick." */
  208.     for(;;)
  209.         pwait(NULL);
  210. }
  211. /* Process used by processes that want to kill themselves */
  212. void
  213. killer(i,v1,v2)
  214. int i;
  215. void *v1;
  216. void *v2;
  217. {
  218.     struct proc *pp;
  219.     struct mbuf *bp;
  220.  
  221.     for(;;){
  222.         while(Killq == NULLBUF)
  223.             pwait(&Killq);
  224.         bp = dequeue(&Killq);
  225.         pullup(&bp,(char *)&pp,sizeof(pp));
  226.         free_p(bp);
  227.         if(pp != Curproc)    /* We're immortal */
  228.             killproc(pp);
  229.     }                        
  230. }
  231.  
  232. #ifdef    SUSPEND_PROC
  233. /* Inhibit a process from running */
  234. void
  235. suspend(pp)
  236. struct proc *pp;
  237. {
  238.     if(pp == NULLPROC)
  239.         return;
  240.     if(pp != Curproc)
  241.         delproc(pp);    /* Running process isn't on any list */
  242.     pp->state |= SUSPEND;
  243.     if(pp != Curproc)
  244.         addproc(pp);    /* pwait will do it for us */
  245.     else
  246.         pwait(NULL);
  247. }
  248. /* Restart suspended process */
  249. void
  250. resume(pp)
  251. struct proc *pp;
  252. {
  253.     if(pp == NULLPROC)
  254.         return;
  255.     delproc(pp);    /* Can't be Curproc! */
  256.     pp->state &= ~SUSPEND;
  257.     addproc(pp);
  258. }
  259. #endif    /* SUSPEND_PROC */
  260.  
  261. /* Wakeup waiting process, regardless of event it's waiting for. The process
  262.  * will see a return value of "val" from its pwait() call.
  263.  */
  264. void
  265. alert(pp,val)
  266. struct proc *pp;
  267. int val;
  268. {
  269.     if(pp == NULLPROC)
  270.         return;
  271. #ifdef    notdef
  272.     if((pp->state & WAITING) == 0)
  273.         return;
  274. #endif
  275. #ifdef    PROCTRACE
  276.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  277.     fflush(stdout);
  278. #endif
  279.     if(pp != Curproc)
  280.         delproc(pp);
  281.     pp->state &= ~WAITING;
  282.     pp->retval = val;
  283.     pp->event = 0;
  284.     if(pp != Curproc)
  285.         addproc(pp);
  286. }
  287.  
  288. /* Post a wait on a specified event and give up the CPU until it happens. The
  289.  * null event is special: it means "I don't want to block on an event, but let
  290.  * somebody else run for a while". It can also mean that the present process
  291.  * is terminating; in this case the wait never returns.
  292.  *
  293.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  294.  * arg in an alert() call. Pwait must not be called from interrupt level.
  295.  *
  296.  * Note that pwait can run with interrupts enabled even though it examines
  297.  * a few global variables that can be modified by psignal at interrupt time.
  298.  * These *seem* safe.
  299.  */
  300. int
  301. pwait(event)
  302. void *event;
  303. {
  304.     register struct proc *oldproc;
  305.     int tmp;
  306.  
  307.     extern int WDTick;
  308.     extern int WDCurr;
  309.  
  310.     WDCurr = WDTick;        /* reset watchdog timer value */
  311.  
  312.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  313.         if(Stkchk)
  314.             chkstk();
  315.  
  316.         if(event == NULL){
  317.             /* Special case; just give up the processor.
  318.              *
  319.              * Optimization: if nothing else is ready, just return.
  320.              */
  321.             if(Rdytab == NULLPROC){
  322.                 return 0;
  323.             }
  324.         } else {
  325.             /* Post a wait for the specified event */
  326.             Curproc->event = event;
  327.             Curproc->state = WAITING;
  328.         }
  329.         addproc(Curproc);
  330.     }
  331.     /* Look for a ready process and run it. If there are none,
  332.      * loop or halt until an interrupt makes something ready.
  333.      */
  334.     while(Rdytab == NULLPROC){
  335.         /* Give system back to upper-level multitasker, if any.
  336.          * Note that this function enables interrupts internally
  337.          * to prevent deadlock, but it restores our state
  338.          * before returning.
  339.          */
  340.         kbint();    /***/
  341.         giveup();
  342.     }
  343.     /* Remove first entry from ready list */
  344.     oldproc = Curproc;
  345.     Curproc = Rdytab;
  346.     delproc(Curproc);
  347.  
  348.     /* Now do the context switch.
  349.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  350.      *
  351.      * If the old process has gone away, simply load the new process's
  352.      * environment. Otherwise, save the current process's state. Then if
  353.      * this is still the old process, load the new environment. Since the
  354.      * new task will "think" it's returning from the setjmp() with a return
  355.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  356.      * would otherwise cause an infinite loop.
  357.      */
  358. #ifdef    PROCTRACE
  359.     if(strcmp(oldproc->name,Curproc->name) != 0){
  360.           printf("pwait -> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  361.         fflush(stdout);
  362.     }
  363. #endif
  364.     /* Note use of comma operator to save old interrupt state only if
  365.      * oldproc is non-null
  366.      */
  367.     if(oldproc == NULLPROC
  368.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
  369.         /* We're still running in the old task; load new task context.
  370.          * The interrupt state is restored here in case longjmp
  371.          * doesn't do it (e.g., systems other than Turbo-C).
  372.          */
  373.         restore(Curproc->i_state);
  374.         longjmp(Curproc->env,1);
  375.     }
  376.     /* At this point, we're running in the newly dispatched task */
  377.     tmp = Curproc->retval;
  378.     Curproc->retval = 0;
  379.  
  380.     /* Also restore the true interrupt state here, in case the longjmp
  381.      * DOES restore the interrupt state saved at the time of the setjmp().
  382.      * This is the case with Turbo-C's setjmp/longjmp.
  383.      */
  384.     restore(Curproc->i_state);
  385.     return tmp;
  386. }
  387.  
  388. /* Make ready the first 'n' processes waiting for a given event. The ready
  389.  * processes will see a return value of 0 from pwait().  Note that they don't
  390.  * actually get control until we explicitly give up the CPU ourselves through
  391.  * a pwait(). Psignal may be called from interrupt level. It returns the
  392.  * number of processes that were woken up.
  393.  */
  394. int
  395. psignal(event,n)
  396. void *event;    /* Event to signal */
  397. int n;        /* Max number of processes to wake up */
  398. {
  399.     register struct proc *pp;
  400.     struct proc *pnext;
  401.     int i_state;
  402.     unsigned int hashval;
  403.     int cnt = 0;
  404.  
  405.     if(Stkchk)
  406.         chkstk();
  407.  
  408.     if(event == NULL)
  409.         return 0;        /* Null events are invalid */
  410.  
  411.     /* n = 0 means "signal everybody waiting for this event" */
  412.     if(n == 0)
  413.         n = 65535;
  414.  
  415.     hashval = phash(event);
  416.     i_state = dirps();
  417.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  418.         pnext = pp->next;
  419.         if(pp->event == event){
  420. #ifdef    PROCTRACE
  421.             if(i_state){
  422.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  423.                  ptol(pp),pp->name);
  424.                 fflush(stdout);
  425.             }
  426. #endif
  427.             delproc(pp);
  428.             pp->state &= ~WAITING;
  429.             pp->retval = 0;
  430.             pp->event = NULL;
  431.             addproc(pp);
  432.             n--;
  433.             cnt++;
  434.         }
  435.     }
  436. #ifdef    SUSPEND_PROC
  437.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  438.         pnext = pp->next;
  439.         if(pp->event == event){
  440. #ifdef    PROCTRACE
  441.             if(i_state){
  442.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  443.                  ptol(pp),pp->name);
  444.                 fflush(stdout);
  445.             }
  446. #endif /* PROCTRACE */
  447.             delproc(pp);
  448.             pp->state &= ~WAITING;
  449.             pp->event = 0;
  450.             pp->retval = 0;
  451.             addproc(pp);
  452.             n--;
  453.             cnt++;
  454.         }
  455.     }
  456. #endif    /* SUSPEND_PROC */
  457.     restore(i_state);
  458.     return cnt;
  459. }
  460.  
  461. /* Rename a process */
  462. void
  463. chname(pp,newname)
  464. struct proc *pp;
  465. char *newname;
  466. {
  467.     free(pp->name);
  468.     pp->name = strdup(newname);
  469. }
  470. /* Remove a process entry from the appropriate table */
  471. static void
  472. delproc(entry)
  473. register struct proc *entry;    /* Pointer to entry */
  474. {
  475.     int i_state;
  476.  
  477.     if(entry == NULLPROC)
  478.         return;
  479.  
  480.     i_state = dirps();
  481.     if(entry->next != NULLPROC)
  482.         entry->next->prev = entry->prev;
  483.     if(entry->prev != NULLPROC){
  484.         entry->prev->next = entry->next;
  485.     } else {
  486.         switch(entry->state){
  487.         case READY:
  488.             Rdytab = entry->next;
  489.             break;
  490.         case WAITING:
  491.             Waittab[phash(entry->event)] = entry->next;
  492.             break;
  493. #ifdef    SUSPEND_PROC
  494.         case SUSPEND:
  495.         case SUSPEND|WAITING:
  496.             Susptab = entry->next;
  497.             break;
  498. #endif
  499.         }
  500.     }
  501.     restore(i_state);
  502. }
  503. /* Append proc entry to end of appropriate list */
  504. static void
  505. addproc(entry)
  506. register struct proc *entry;    /* Pointer to entry */
  507. {
  508.     register struct proc *pp;
  509.     struct proc **head;
  510.     int i_state;
  511.  
  512.     if(entry == NULLPROC)
  513.         return;
  514.  
  515.     switch(entry->state){
  516.     case READY:
  517.         head = &Rdytab;
  518.         break;
  519.     case WAITING:
  520.         head = &Waittab[phash(entry->event)];
  521.         break;
  522. #ifdef    SUSPEND_PROC
  523.     case SUSPEND:
  524.     case SUSPEND|WAITING:
  525.         head = &Susptab;
  526.         break;
  527. #endif
  528.     }
  529.     entry->next = NULLPROC;
  530.     i_state = dirps();
  531.     if(*head == NULLPROC){
  532.         /* Empty list, stick at beginning */
  533.         entry->prev = NULLPROC;
  534.         *head = entry;
  535.     } else {
  536.         /* Find last entry on list */
  537.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  538.             ;
  539.         pp->next = entry;
  540.         entry->prev = pp;
  541.     }
  542.     restore(i_state);
  543. }
  544.